package com.e3.template.tgf;

import java.util.ArrayList;
import java.util.List;

import com.e3.web.core.client.GridListener;
import com.e3.web.core.client.ListenerManager;
import com.e3.web.core.model.ModelHelper;
import com.e3.web.core.model.SuperModel;
import com.extjs.gxt.ui.client.data.ListLoader;
import com.extjs.gxt.ui.client.event.GridEvent;
import com.extjs.gxt.ui.client.event.SelectionChangedEvent;
import com.extjs.gxt.ui.client.event.SelectionChangedListener;
import com.extjs.gxt.ui.client.store.ListStore;
import com.extjs.gxt.ui.client.widget.Component;
import com.extjs.gxt.ui.client.widget.LayoutContainer;
import com.extjs.gxt.ui.client.widget.grid.ColumnConfig;
import com.extjs.gxt.ui.client.widget.grid.ColumnModel;
import com.extjs.gxt.ui.client.widget.grid.EditorGrid;
import com.extjs.gxt.ui.client.widget.grid.Grid;
import com.extjs.gxt.ui.client.widget.grid.GridSelectionModel;
import com.extjs.gxt.ui.client.widget.layout.FitLayout;
import com.extjs.gxt.ui.client.widget.menu.Menu;
import com.google.gwt.user.client.Element;

public abstract class TGFGridPanel<D extends SuperModel> extends LayoutContainer {
	
	protected ModelHelper<D> modelHelper = new ModelHelper<D>();
	
	protected ListenerManager<D> listenerManager = new ListenerManager<D>();
	
	private Component maskComponent;
	
	private Grid<D> grid ;
	private ListStore<D> store;
	private GridSelectionModel<D> gridSelectionModel;
	
	public void addGridListener(GridListener<D> listener){
		listenerManager.addGridListener(listener);
	}

	@Override
	protected void onRender(Element parent, int index) {
		super.onRender(parent, index);
		setLayout(new FitLayout());
		
		initContent();
	}
	
	protected void initContent(){
		add(getGrid());
	}
	
	protected Grid<D> getCurrentGrid(){
		return getGrid();
	}
	
	@SuppressWarnings({ "rawtypes"})
	protected ListStore<D> getGridStore(){
		if(store==null){
			ListLoader loader = getGridLoader();
			store = createGridStore(loader);
		}
		return store;
	}

	protected Grid<D> getGrid(){
		if (grid == null) {
			List<ColumnConfig> configs = getGridColumnConfigs();
			ColumnModel cm = new ColumnModel(configs);
			
			grid = new EditorGrid<D>(getGridStore(), cm){
				protected void onDoubleClick(GridEvent<D> e) {
				    onGridRowDoubleClicked(e.getModel());
				}
			};		
			grid.setSelectionModel(getGridSelectionModel());
			afterCreateGrid(grid);
		}
		return grid;
	}
	
	@SuppressWarnings("rawtypes")
	protected ListLoader getGridLoader(){
		return null;
	}
	
	@SuppressWarnings({ "rawtypes", "unchecked" })
	protected ListStore<D> createGridStore(ListLoader loader){
		ListStore listStore = null;
		if(loader == null){
			listStore = new ListStore<D>();
		}
		else{
			listStore = new ListStore(loader);
		}
		listStore.setModelComparer(modelHelper.getModelComparer());
		listStore.setKeyProvider(modelHelper.getModelKeyProvider());
		return listStore;
	}
	
	public void setGridContextMenu(Menu menu){
		beforeSetGridContextMenu(menu);
		getGrid().setContextMenu(menu);
	}
	
	public GridSelectionModel<D> getGridSelectionModel(){
		if(gridSelectionModel==null){
			gridSelectionModel = new GridSelectionModel<D>();
			gridSelectionModel.addSelectionChangedListener(new SelectionChangedListener<D>(){
				@Override
				public void selectionChanged(SelectionChangedEvent<D> se) {
					D model = se.getSelectedItem();
					onGridSelectionChanged(model);
				}
			});
		}
		return gridSelectionModel;
	}
	
	public void setSelectValue(D model){
		if(model==null){
			return;
		}
		List<D> models = new ArrayList<D>(1);
		models.add(model);
		innerSetSelectValues(getCurrentGrid().getSelectionModel(),models);
	}
	
	protected void innerSetSelectValues(GridSelectionModel<D> sm,List<D> models){
		sm.setSelection(models);
	}
	
	public void setSelectValues(List<D> models){
		innerSetSelectValues(getCurrentGrid().getSelectionModel(),models);
	}
	
	protected void onGridSelectionChanged(D model) {
		listenerManager.notifyGridSelectChanged(model);
	}
	
	public List<D> getSelectedModels(){
		return getCurrentGrid().getSelectionModel().getSelectedItems();
	}
	
	public void removeValues(List<D> models){
		innerRemoveValues(getCurrentGrid().getStore(), models);
	}
	
	protected void innerRemoveValues(ListStore<D> gridStore,List<D> models){
		if(models == null || models.size()==0){
			return;
		}
		for (D model : models) {
			gridStore.remove(model);
		}
	}
	
	public void addGridValue(D model){
		innerAddGridValue(getCurrentGrid().getStore(),model);
	}

	protected void innerAddGridValue(ListStore<D> gridStore,D model){
		gridStore.add(model);
		setSelectValue(model);
	}
	
	public void setGridValues(List<D> models){
		innerSetGridValues(getCurrentGrid().getStore(),models);
	}
	
	protected void innerSetGridValues(ListStore<D> gridStore,List<D> models){
		gridStore.removeAll();
		if(models!=null&&models.size()>0){
			gridStore.add(models);
			setSelectValue(models.get(0));
		}
		else{
			onGridSelectionChanged(null);
		}
	}
	
	public void refreshGridModel(D model){
		innerRefreshGridModel(getCurrentGrid().getStore(), model);
	}
	
	protected void innerRefreshGridModel(ListStore<D> gridStore,D model){
		if(model==null||gridStore==null){
			return;
		}
		List<D> models = gridStore.getModels();
		boolean isUpdate = false;
		if(models!=null&&models.size()>0){
			for (D m : models) {
				if(m.getId().equals(model.getId())){
					isUpdate = true;
					break;
				}
			}
			if(isUpdate){
				gridStore.update(model);
				setSelectValue(model);
				return;
			}
		}
		List<D> ms = new ArrayList<D>(1);
		ms.add(model);
		gridStore.add(ms);
		setSelectValue(model);
	}
	
	protected void onGridRowDoubleClicked(D model){
		listenerManager.notifyGridRowDoubleClicked(model);
	}

	public Component getMaskComponent() {
		return maskComponent;
	}

	public void setMaskComponent(Component maskComponent) {
		this.maskComponent = maskComponent;
	}
	
	public void beforeSetGridContextMenu(Menu menu){
		
	}
		
	protected void afterCreateGrid(Grid<D> grid){
		
	}
	
	protected abstract List<ColumnConfig> getGridColumnConfigs();

}
